package cn.highedu.mvc;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 映射处理器，用于处理请求和对应控制器方法之间映射
 * 根据用户请求路径， 找到对应的控制器方法
 * HandlerMapping 使用单例模式创建对象
 */
public class HandlerMapping {
    //单例模式
    private static HandlerMapping instance = new HandlerMapping();
    private HandlerMapping() {
        try {
            initHandlers();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static HandlerMapping getInstance() {
        return instance;
    }
    /**
     * 定义一个map存储请求路径和控制器方法的映射关系
     * "/register" -> register()
     * "/users" -> users()
     * "/submit" -> submit()
     * ...
     */
    private Map<String, Method> handlers = new HashMap<>();

    /**
     * 根据请求的URI找到对应的控制器方法
     * @param uri 请求路径
     * @return 控制器方法
     */
    public Method getHandlerMethod(String uri){
        return handlers.get(uri);
    }

    /**
     * 初始化映射关系，找到标注了@Controller的类，再查找
     * 其中标注了@RequestMapping注解的方法，将url和方法
     * 对应关系存储到 handlers 集合
     */
    private void initHandlers() throws Exception {
        //找到控制器的包
        File root = new File(
                HandlerMapping.class.getClassLoader().getResource(".").toURI()
        );
        File mvcPackage = new File(root, "/cn/highedu/mvc");
        System.out.println(mvcPackage);
        //找到包中所有 class 文件
        File[] files = mvcPackage.listFiles(file->file.getName().endsWith(".class"));
        for (File file: files){
            //遍历每个 class 文件
            System.out.println(file);
            //根据文件名创建类的全名
            String filename = file.getName();
            System.out.println(filename);
            String className = "cn.highedu.mvc."+filename.substring(0, filename.lastIndexOf("."));
            System.out.println(className);
            //使用类加载器，加载类, 加载以后就可以读取注解
            Class cls = Class.forName(className);
            //在类上找是否标注了 @Controller注解
            if (cls.isAnnotationPresent(Controller.class)){
                System.out.println(cls + "标注了@Controller注解");
                //查找当前类的全部的方法
                Method[] methods = cls.getDeclaredMethods();
                //查找类的上那个方法标注了 @RequestMapping 注解
                for (Method method: methods){
                    if (method.isAnnotationPresent(RequestMapping.class)){
                        System.out.println("找到了 @RequestMapping： " + method);
                        //读取注解的属性
                        RequestMapping ann = method.getAnnotation(RequestMapping.class);
                        String uri = ann.value();
                        //将找到的uri和对应的方法存储到 map 集合handlers中
                        handlers.put(uri, method);
                        System.out.println(uri + ":" + method);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        HandlerMapping handlerMapping = HandlerMapping.getInstance();
        handlerMapping.initHandlers();
        String uri = "/register";
        Method method = handlerMapping.handlers.get(uri);
        System.out.println("找到：" + method);
    }
}
